package de.ghost23.common.statemachine {
	import de.ghost23.common.process.ACommand;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	/**
	 * A State instance defines a ACommand, that is executed, once the state is entered.
	 * It also defines zero, one or multiple states as possible followers to this one.
	 * The identifier is just for debugging purposes and is recommended, but not essential.
	 * @example
	 * <p>It is recommended to build a class, that holds all the states, like this:</p>
	<listing version="3.0">package xmlStateMachine {
	import de.ghost23.common.statemachine.State;

	public class XMLStates {

		// The states
		public static const EMPTY_IDLE:State        = new State("EMPTY_IDLE");
		public static const FILE_REQUESTING:State   = new State("FILE_REQUESTING");
		public static const FILE_LOADED:State       = new State("FILE_LOADED");
		public static const FILE_LOADERROR:State    = new State("FILE_LOADERROR");
		public static const XML_PARSING:State       = new State("XML_PARSING");
		public static const XML_PARSED:State        = new State("XML_PARSED");
		public static const XML_REJECTED:State      = new State("XML_REJECTED");
		public static const FILE_UNLOADING:State    = new State("FILE_UNLOADING");
	}
}</listing>
	 * <p>You can the pass this class directly into the state machine and it will use it
	 * as an enumeration object. Of course, you can also build a simple object to do the
	 * same, but then you loose code completion in your editor and some compiler checks.</p>
	 * @author Sven Busse
	 * @version 1.0
	 * @see de.ghost23.common.statemachine.StateMachine
	 */
	public class State {

		private var _identifier:String;
		private var _inputCommand:Class;

		/**
		 * Defines state(s), that follow(s) this one, when a respective input reaches
		 * the state machine.
		 * <p>Define a state per event, like this:</p>
		 <listing version="3.0">myState.stateAfterEvent[followingState] = EVENT_TYPE;</listing>
		 * <p>This effectively means, that if the state machine receives an incoming signal
		 * with the String of EVENT_TYPE, it will move to the state followingState (which is
		 * an instance of State again).</p>
		 */
		public const stateAfterEvent:Dictionary = new Dictionary();

		/**
		 * You set a state to transient to make clear, that this state will only be temporary
		 * and that the state machine will immediately try to move to the next state, if it
		 * has enough information to choose the correct path.
		 * <p>If a state only has one follower, the state machine will always choose that one, if
		 * the this state is transient. If it has multiple followers and a target state has been
		 * set in the state machine, the state machine will automatically choose the correct following state to
		 * reach the target state, if this state is transient.</p>
		 */
		public var transient:Boolean = false;

		/**
		 * Constructs a new state. You should give it an identifiert for better debugging.
		 * You can give it an input command here.
		 * @param	identifier The identifier is just for debugging purposes and is recommended, but not essential.
		 * @param	inputCommand A class reference to an ACommand, that is executed, once the state is entered. Optional.
		 */
		public function State(identifier:String, inputCommand:Class=null) {
			_identifier = identifier;
			if(inputCommand != null) this.inputCommand = inputCommand;
		}

		/**
		 * The identifier is just for debugging purposes and is recommended, but not essential. It can
		 * only be set in the constructor of this state.
		 */
		public function get identifier():String {
			return _identifier;
		}

		/**
		 * A class reference to an ACommand, that is executed, once the state is entered. Optional.
		 */
		public function get inputCommand():Class {
			return _inputCommand;
		}

		public function set inputCommand(value:Class):void {
			if(value == null) return;
			else if(!(new value() is ACommand)) throw new ArgumentError("'value' is not of type ACommand! (is " + getQualifiedClassName(value) + ")");
			_inputCommand = value;
		}
	}
}